package com.shnu.work.controller;

import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.shnu.work.dto.UserDataWhileUsingDTO;
import com.shnu.work.entity.AdministrationInformationEntity;
import com.shnu.work.entity.SystemInformationEntity;
import com.shnu.work.entity.UserDataWhileUsingEntity;
import com.shnu.work.entity.UserInformationEntity;
import com.shnu.work.service.IAdministrationInformationService;
import com.shnu.work.service.ISystemInformationService;
import com.shnu.work.service.IUserDataWhileUsingService;
import com.shnu.work.service.IUserInformationService;
import com.shnu.work.util.NewRedisUtils;
import com.shnu.work.util.RedisUtils;
import com.spoon.pass.encrypt.EncryptDecrypt;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.apache.ibatis.annotations.Param;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpSession;
import java.text.ParseException;
import java.util.List;
import java.util.Optional;
import java.util.Set;

/**
 * @author Kanna Hashimoto
 */
@Slf4j
@Controller
@RequestMapping("/admin")
public class AdminController {
    private final Gson gson = new Gson();
    private final String ENCRYPT_KEY = "developedByTongHao";
    @Autowired
    private IUserInformationService userInformationService;
    @Autowired
    private IUserDataWhileUsingService userDataWhileUsingService;
    @Autowired
    private ISystemInformationService systemInformationService;
    @Autowired
    private IAdministrationInformationService administrationInformationService;
    @Autowired
    private RedisUtils redisUtils;

    @RequestMapping("/backToAdmin")
    public String backToAdmin() {
        return "/admin/starter";
    }

    @RequestMapping("/getSensorInfo")
    public ModelAndView getSensorInfo(ModelAndView modelAndView, HttpSession session) {
        String adminUser = (String) session.getAttribute("admin_user");
        log.info("admin getSensorInfo adminUser:{}", adminUser);
        listSensorData(modelAndView, adminUser);
        modelAndView.setViewName("/admin/sensorinfo");
        return modelAndView;
    }

    private void listSensorData(ModelAndView modelAndView, String adminUser) {
        if (!StringUtils.isBlank(adminUser)) {
            NewRedisUtils redisUtils = NewRedisUtils.getRedisUtil();
            UserInformationEntity userInfo = userInformationService.getUserInformationEntityByUserAccount(adminUser);
            log.info("userInfo:{}", gson.toJson(userInfo));
            List<UserDataWhileUsingEntity> userDataList =
                    userDataWhileUsingService.listAllUndeleted();
            log.info("userDataList Before Redis:{}", gson.toJson(userDataList));
            Set<String> redisUserData = redisUtils.keys(2, "location_info_*");
            redisUserData.stream().map(key -> redisUtils.get(2, key)).map(value -> gson.fromJson(value, UserDataWhileUsingEntity.class)).filter(userDataWhileUsingEntity -> new Integer(1).equals(userDataWhileUsingEntity.getIsDeleted())).forEach(userDataList::add);
            log.info("userDataList After Redis:{}", gson.toJson(userDataList));
            modelAndView.addObject("userDataList", userDataList);
        }
    }

    @RequestMapping("/saveNewRecord")
    public ModelAndView saveNewRecord(ModelAndView modelAndView, HttpSession session, UserDataWhileUsingDTO userDataWhileUsingDto) throws ParseException {
        log.info("userDataWhileUsingDto:{}", gson.toJson(userDataWhileUsingDto));
        String loginUser = (String) session.getAttribute("admin_user");
        //从redis中获取用户信息
        String loginUserJson = redisUtils.get("login_user_" + loginUser);
        UserInformationEntity loginUserEntity = gson.fromJson(loginUserJson, UserInformationEntity.class);
        log.info("loginUserEntity:{}", gson.toJson(loginUserEntity));

        UserDataWhileUsingEntity userDataWhileUsingEntity = new UserDataWhileUsingEntity();
        BeanUtils.copyProperties(userDataWhileUsingDto, userDataWhileUsingEntity);
        userDataWhileUsingEntity.setUserDocumentTime(DateUtils.parseDate(userDataWhileUsingDto.getUserDocumentTime(), "yyyy-MM-dd"));
        userDataWhileUsingEntity.setUserId(loginUserEntity.getId());
        userDataWhileUsingEntity.setUserName(loginUserEntity.getUserName());

        UserDataWhileUsingEntity save = userDataWhileUsingService.save(userDataWhileUsingEntity);

        listSensorData(modelAndView, loginUser);
        return modelAndView;
    }

    @RequestMapping("/removeRecord/{userDocumentTime}/{deviceId}/{userAccount}")
    public ModelAndView removeRecord(ModelAndView modelAndView,
                                     HttpSession session,
                                     @PathVariable("userDocumentTime") String userDocumentTime,
                                     @PathVariable("deviceId") Long deviceId,
                                     @PathVariable("userAccount") String userAccount) {
        NewRedisUtils redisUtils = NewRedisUtils.getRedisUtil();
        // 某一个时间点某一个用户的记录，查看在这个时刻有没有这样的一条记录
        String key = "location_info_" + userAccount + "_" + userDocumentTime.replace(".0", "").replace(" ", "_").replace("-", ":");
        log.info("removeRecord key:{}", key);
        String oldUserDataStr = redisUtils.get(2, key);
        log.info("removeRecord oldUserDataStr:{}", oldUserDataStr);
        if (!StringUtils.isBlank(oldUserDataStr)) {
            UserDataWhileUsingEntity oldUserData = gson.fromJson(oldUserDataStr, new TypeToken<UserDataWhileUsingEntity>() {
            }.getType());
            oldUserData.setIsDeleted(1);
            redisUtils.set(2, key, gson.toJson(oldUserData));
        } else {
            log.info("removeRecord userDocumentTime:{}", userDocumentTime);
            Integer oldUserData = userDataWhileUsingService.removeUserDataByUserDocumentTimeAndUserName(userDocumentTime, deviceId);
            log.info("removeRecord oldUserData:{}", gson.toJson(oldUserData));
        }

        String adminUser = (String) session.getAttribute("admin_user");
        log.info("admin getSensorInfo adminUser:{}", adminUser);
        listSensorData(modelAndView, adminUser);

        modelAndView.setViewName("/admin/sensorinfo");
        return modelAndView;
    }

    @RequestMapping("/listUserInfo")
    public ModelAndView listUserInfo(ModelAndView modelAndView) {
        List<UserInformationEntity> userInformationEntities = this.userInformationService.listAllUndeletedUsers();
        log.info("listUserInfo userInformationEntities:{}", gson.toJson(userInformationEntities));
        userInformationEntities.forEach(userInformationEntity -> userInformationEntity.setUserPassword(EncryptDecrypt.decrypt(userInformationEntity.getUserPassword(), ENCRYPT_KEY)));
        modelAndView.addObject("users", userInformationEntities);
        modelAndView.setViewName("/admin/userinfo");
        return modelAndView;
    }

    /**
     * 新增用户
     *
     * @param modelAndView          ModelAndView
     * @param userInformationEntity 要插入表的用户
     * @return 跳转地址
     */
    @PostMapping(value = "/saveNewUser")
    public ModelAndView saveNewUser(ModelAndView modelAndView, UserInformationEntity userInformationEntity) {
        log.info("saveNewUser user:{}", gson.toJson(userInformationEntity));
        // 密码加密
        userInformationEntity.setUserPassword(EncryptDecrypt.encrypt(userInformationEntity.getUserPassword(), ENCRYPT_KEY));
        userInformationEntity.setIsDeleted(0);
        UserInformationEntity returnEntity = userInformationService.saveUser(userInformationEntity);
        if (returnEntity != null) {
            modelAndView.addObject("msg", "success");
            List<UserInformationEntity> userInformationEntities = this.userInformationService.listAllUndeletedUsers();
            log.info("saveNewUser users:{}", gson.toJson(userInformationEntities));
            modelAndView.addObject("users", userInformationEntities);
            modelAndView.setViewName("/admin/userinfo");
        }

        return modelAndView;
    }

    @RequestMapping(value = "/removeUser/{id}")
    public ModelAndView removeUser(ModelAndView modelAndView, @PathVariable("id") Long id) {
        log.info("removeUser id:{}", id);
        Integer integer = this.userInformationService.removeUserById(id);
        log.info("removeUser removelines:{}", integer);
        List<UserInformationEntity> userInformationEntities = this.userInformationService.listAllUndeletedUsers();
        log.info("removeUser users:{}", gson.toJson(userInformationEntities));
        modelAndView.addObject("users", userInformationEntities);

        modelAndView.setViewName("/admin/userInfo");

        return modelAndView;
    }

    @RequestMapping(value = "/updateUser/{id}")
    public ModelAndView updateUser(ModelAndView modelAndView,
                                   @PathVariable("id") Long id,
                                   @Param("userName") String userName,
                                   @Param("userAccount") String userAccount,
                                   @Param("userSex") Integer userSex,
                                   @Param("userSignature") String userSignature,
                                   @Param("userNumOfDevice") Short userNumOfDevice,
                                   @Param("userPassword") String userPassword) {
        log.info("updateUser id:{}", id);
        Optional<UserInformationEntity> user = userInformationService.findUserById(id);
        try {
            if (user.isPresent()) {
                user.get().setUserName(userName);
                user.get().setUserAccount(userAccount);
                user.get().setUserPassword(EncryptDecrypt.encrypt(userPassword, ENCRYPT_KEY));
                user.get().setUserSex(userSex);
                user.get().setUserSignature(userSignature);
                user.get().setUserNumOfDevice(userNumOfDevice);
                log.info("updateUser user:{}", gson.toJson(user));
                userInformationService.saveUser(user.get());
            }
        } catch (Exception exception) {
            exception.printStackTrace();
        }

        List<UserInformationEntity> userInformationEntities = this.userInformationService.listAllUndeletedUsers();
        userInformationEntities.forEach(userInformationEntity -> userInformationEntity.setUserPassword(EncryptDecrypt.decrypt(userInformationEntity.getUserPassword(), ENCRYPT_KEY)));
        log.info("updateUser users:{}", gson.toJson(userInformationEntities));
        modelAndView.addObject("users", userInformationEntities);

        modelAndView.setViewName("/admin/userInfo");

        return modelAndView;
    }

    @RequestMapping("/listSysInfo")
    public ModelAndView listSysInfo(ModelAndView modelAndView) {
        List<SystemInformationEntity> sysInfos = this.systemInformationService.listAllUndeletedSysInfo();
        log.info("listUserInfo sysInfos:{}", gson.toJson(sysInfos));
        modelAndView.addObject("sysInfos", sysInfos);
        modelAndView.setViewName("/admin/sysinfo");
        return modelAndView;
    }

    @RequestMapping("/saveNewSysInfo")
    public ModelAndView saveNewSysInfo(ModelAndView modelAndView, @Param("noteOfDutyFree") String noteOfDutyFree) {
        SystemInformationEntity newInfo = new SystemInformationEntity();
        newInfo.setNoteOfDutyFree(noteOfDutyFree);
        newInfo.setNoteOf2("0");
        newInfo.setIsDeleted(0);
        SystemInformationEntity systemInformationEntity = systemInformationService.saveNewSysInfo(newInfo);

        List<SystemInformationEntity> sysInfos = this.systemInformationService.listAllUndeletedSysInfo();
        log.info("saveNewSysInfo sysInfos:{}", gson.toJson(sysInfos));
        modelAndView.addObject("sysInfos", sysInfos);
        modelAndView.setViewName("/admin/sysinfo");

        return modelAndView;
    }

    @RequestMapping("/updateAvailableStatus/{id}")
    public ModelAndView updateAvailableStatus(ModelAndView modelAndView, @PathVariable("id") Long id) {
        this.systemInformationService.clearAllAvailableStatus();
        this.systemInformationService.updateAvailableStatusById(id);
        Optional<SystemInformationEntity> sysInfoById = this.systemInformationService.getSysInfoById(id);
        NewRedisUtils redisUtil = NewRedisUtils.getRedisUtil();
        sysInfoById.ifPresent(systemInformationEntity -> redisUtil.set(3, "sys_info", systemInformationEntity.getNoteOfDutyFree()));

        List<SystemInformationEntity> sysInfos = this.systemInformationService.listAllUndeletedSysInfo();
        log.info("saveNewSysInfo sysInfos:{}", gson.toJson(sysInfos));
        modelAndView.addObject("sysInfos", sysInfos);
        modelAndView.setViewName("/admin/sysinfo");

        return modelAndView;
    }

    @RequestMapping("/updateSysInfo/{id}")
    public ModelAndView updateSysInfo(ModelAndView modelAndView, @PathVariable("id") Long id, @Param("noteOfDutyFreeUpdate") String noteOfDutyFreeUpdate) {
        Optional<SystemInformationEntity> sysInfoById = this.systemInformationService.getSysInfoById(id);
        sysInfoById.ifPresent(systemInformationEntity -> systemInformationEntity.setNoteOfDutyFree(noteOfDutyFreeUpdate));

        List<SystemInformationEntity> sysInfos = this.systemInformationService.listAllUndeletedSysInfo();
        log.info("saveNewSysInfo sysInfos:{}", gson.toJson(sysInfos));
        modelAndView.addObject("sysInfos", sysInfos);
        modelAndView.setViewName("/admin/sysinfo");

        return modelAndView;
    }

    @RequestMapping("/removeSysInfo/{id}")
    public ModelAndView removeSysInfo(ModelAndView modelAndView, @PathVariable("id") Long id) {
        Integer integer = systemInformationService.removeSysInfoById(id);

        List<SystemInformationEntity> sysInfos = this.systemInformationService.listAllUndeletedSysInfo();
        log.info("saveNewSysInfo sysInfos:{}", gson.toJson(sysInfos));
        modelAndView.addObject("sysInfos", sysInfos);
        modelAndView.setViewName("/admin/sysinfo");

        return modelAndView;
    }

    @RequestMapping("/listAdminInfo")
    public ModelAndView listAdminInfo(ModelAndView modelAndView) {
        List<AdministrationInformationEntity> adminInfo = this.administrationInformationService.listAllAdminInfo();
        log.info("listAdminInfo adminInfo:{}", gson.toJson(adminInfo));
        for (AdministrationInformationEntity administrationInformationEntity : adminInfo) {
            administrationInformationEntity.setAdministrationPassword(EncryptDecrypt.decrypt(administrationInformationEntity.getAdministrationPassword(), ENCRYPT_KEY));
        }
        modelAndView.addObject("admins", adminInfo);
        modelAndView.setViewName("/admin/admininfo");

        return modelAndView;
    }

    @RequestMapping("/listUserDataByIdAndTime")
    public ModelAndView listUserDataByIdAndTime(ModelAndView modelAndView,
                                                @Param("lUserDocumentTime") String lUserDocumentTime,
                                                @Param("lDeviceId") Long lDeviceId) {
        List<UserDataWhileUsingEntity> allUndeleted = null;
        try {
            if (lDeviceId != null && !StringUtils.isBlank(lUserDocumentTime)) {
                allUndeleted = userDataWhileUsingService.listUserDataByDeviceIdAndUserDocumentTime(lDeviceId, lUserDocumentTime);
            }
            if (lDeviceId == null && !StringUtils.isBlank(lUserDocumentTime)) {
                allUndeleted = userDataWhileUsingService.listUserDataByUserDocumentTime(lUserDocumentTime);
            }
            if (lDeviceId != null && StringUtils.isBlank(lUserDocumentTime)) {
                allUndeleted = userDataWhileUsingService.listUserDataByDeviceId(lDeviceId);
            }
            if (lDeviceId == null && StringUtils.isBlank(lUserDocumentTime)) {
                allUndeleted = userDataWhileUsingService.listAllUndeleted();
            }
        } catch (Exception exception) {
            log.error("查询出错", exception);
            allUndeleted = userDataWhileUsingService.listAllUndeleted();
        }

        log.info("listUserDataByIdAndTime 查询结果:{}", gson.toJson(allUndeleted));

        modelAndView.addObject("userDataList", allUndeleted);
        modelAndView.setViewName("/admin/sensorinfo");
        return modelAndView;
    }
}
